package com.aracky.common.annotation.dataconvert;

import com.aracky.common.annotation.DataDeal;
import com.aracky.common.annotation.dataconvert.dict.DictDto;
import com.aracky.common.annotation.dataconvert.dict.DictUtil;
import com.aracky.common.annotation.dataconvert.user.UserDto;
import com.aracky.common.annotation.dataconvert.user.UserUtil;
import com.aracky.common.vo.CommonResult;
import com.aracky.common.vo.PageVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author zengzhiping
 * @ClassName DataUtil
 * @Description 数据处理---依据注解修饰的属性对对应的字段修饰数据
 * @createTime 2022年06月14日
 */
@Component
@Slf4j
public class DataResultUtil {

    @Autowired
    private DictUtil dIctUtil;

    @Autowired
    private UserUtil userUtil;

    /**
     * 存放对应字典信息
     */
    private Map<String, String> dictInfoMap = new HashMap<>();

    /**
     * 存放用户信息
     */
    private Map<String, String> userInfoMap = new HashMap<>();

    /**
     * 字典参数存放
     */
    private List<DictDto> dictParams = new ArrayList<>();
    /**
     * 用户参数存放
     */
    private List<UserDto> userParams = new ArrayList<>();


    /**
     * 思路:获取结果中的数据，然后反射获取对应的注解，获取注解的值数据，通过注解值，查询对应的数据，然后在设置到对应的字段上
     * 结果：分为分页和单结果，主要是为了获取数据的方式不一样
     * 需要考虑：如果结果对象中包含其他对象，包含集合对象的情况，需要将子属性也要处理
     *
     * @param resultR
     * @param annotation
     * @return
     * @throws Throwable
     */
    public Object translation(Object resultR, DataDeal annotation) throws Throwable {

        // 拿到要返回的数据--这里可以打印下看看内容
        if (Objects.isNull(resultR)) {
            return resultR;
        }
        //如果不是CommonResult返回类型的，
        if(!(resultR instanceof CommonResult)){
            if (setParamValue(resultR,annotation)) {
                return resultR;
            }
            return resultR;
        }

        Object result = ((CommonResult) resultR).getData();
        if(Objects.isNull(result)){
            return resultR;
        }
        if (result instanceof PageVO) {
            // 分页的情况
            ((CommonResult) resultR).setData(translationPage(result, annotation));
            return resultR;
        }
        if (setParamValue(result,annotation)) {
            return result;
        }
        result = translate(result, annotation);
        ((CommonResult) resultR).setData(result);
        return resultR;
    }

    /**
     * 给字典赋值
     *
     * @param result
     * @return
     * @throws IllegalAccessException
     */
    private boolean setParamValue(Object result,DataDeal annotation) throws IllegalAccessException {
        // 获取所有配置注解的code 和实体字段
        Map<String, List> mapping = DataParamUtil.getMapping(result);
        //字典参数
        dictParams = mapping.get(DataParamUtil.DICT_KEY);
        //用户参数
        userParams = mapping.get(DataParamUtil.USER_KEY);

        //两者都没有字段需要转换，直接返回
        if (dictParams.isEmpty() && userParams.isEmpty()) {
            return true;
        }
        //字典参数
        Boolean dictPass = dIctUtil.dealDict(dictParams, dictInfoMap,annotation);

        //用户信息
        Boolean userPass = userUtil.dealUser(userParams, userInfoMap,annotation);

        if (!dictPass && !userPass) {
            //两者都不通过，直接返回
            return true;
        }
        return false;
    }

    /**
     * 转换单个数据
     *
     * @param result
     * @param annotation
     * @return
     */
    private Object translate(Object result, DataDeal annotation) throws IllegalAccessException {
        //处理数据信息
        if (result instanceof List || result instanceof ArrayList) {
            for (Object entity : (List) result) {
                assign(entity, annotation);
            }
        } else {
            assign(result, annotation);
        }

        return result;
    }


    /**
     * 给字段赋值，这里处理字典和用户参数：后面如果还有处理逻辑，继续往后追加集合
     *
     * @param entity
     * @param annotation
     */
    private void assign(Object entity, DataDeal annotation) {
        int dictSize = dictParams.size();
        int userSize = userParams.size();

        int loopIndex = dictSize > userSize ? dictSize : userSize;

        for (int i = 0; i < loopIndex; i++) {
            //字典处理
            if (dictSize > i && annotation.dict()) {
                setDictParam(entity, dictParams, i);
            }
            //用户处理
            if (userSize > i && annotation.user()) {
                setUserParam(entity, userParams, i);
            }
        }

    }

    /**
     * 设置用户参数
     *
     * @param entity
     * @param userParams
     */
    private void setUserParam(Object entity, List<UserDto> userParams, int i) {
        UserDto userDto = userParams.get(i);
        String userId = userDto.getUserId();
        String userField = userDto.getDictField();
        String name = userDto.getName();
        try {
            String[] names = name.split("\\.");
            loopFields(0, entity, names, userField, userId, userInfoMap);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("设置值出错", e.getMessage());
        }
    }


    /**
     * 循环递归设置list中的数据
     *
     * @param curIndex
     * @param entity
     * @param names
     * @param field
     * @param key
     * @param map
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private void loopFields(int curIndex, Object entity, String[] names, String field, String key, Map<String, String> map)
            throws NoSuchFieldException, IllegalAccessException {

        Class c = entity.getClass();
        if (null == c) {
            return;
        }
        if (curIndex > names.length - 1) {
            return;
        }
        if (curIndex == names.length - 1) {
            setFieldValue(curIndex, entity, names, field, key, map);
            return;
        }

        //下面还有数据
        Field f = c.getDeclaredField(names[curIndex]);
        f.setAccessible(true);

        Object result = f.get(entity);
        if (Objects.isNull(result)) {
            return;
        }
        //判断是集合
        if (result instanceof Collection) {
            Collection olist = ((Collection) result);
            if (olist == null || olist.size() == 0) {
                return;
            }
            loopList(curIndex, names, field, key, map, olist);
            return;
        }
        //判断是对象
        loopFields(++curIndex, result, names, field, key, map);

    }

    /**
     * 循环集合
     *
     * @param curIndex
     * @param names
     * @param field
     * @param key
     * @param map
     * @param olist
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private void loopList(int curIndex, String[] names, String field, String key, Map<String, String> map, Collection olist)
            throws NoSuchFieldException, IllegalAccessException {
        for (Object temp : olist) {
            int tempIndex = curIndex;
            Class<?> aClass = temp.getClass();
            if (!DataParamUtil.isExistsModel(aClass.getName())) {
                break;
            }
            loopFields(++tempIndex, temp, names, field, key, map);
        }
    }

    /**
     * 设置字段值
     *
     * @param curIndex
     * @param entity
     * @param names
     * @param field
     * @param key
     * @param map
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private void setFieldValue(int curIndex, Object entity, String[] names, String field, String key, Map<String, String> map)
            throws NoSuchFieldException, IllegalAccessException {
        Class c = entity.getClass();
        //需要赋值了
        if (c != null) {
            Field f = c.getDeclaredField(names[curIndex]);
            f.setAccessible(true);
            Object preValue = f.get(entity);
            if (!Objects.isNull(preValue)) {
                // 需要赋值的字段
                Field fvalue = c.getDeclaredField(field);
                fvalue.setAccessible(true);
                //如果字段值不为空得话，就直接返回
                if (null != fvalue.get(entity)) {
                    return;
                }
                //注意key拼接的格式
                String fieldValue = map.getOrDefault(key + "_" + preValue.toString(), null);
                fvalue.set(entity, fieldValue);
            }
        }
    }


    /**
     * 设置字典参数
     *
     * @param entity
     * @param dictParams
     * @param i
     */
    private void setDictParam(Object entity, List<DictDto> dictParams, int i) {
        DictDto dictDto = dictParams.get(i);
        String code = dictDto.getCode();
        String name = dictDto.getName();
        String dictField = dictDto.getDictField();
        try {
            String[] names = name.split("\\.");
            loopFields(0, entity, names, dictField, code, dictInfoMap);
        } catch (Exception e) {
            log.error("设置值出错", e.getMessage());
        }
    }


    /**
     * 转换多个数据
     *
     * @param resultR
     * @param annotation
     * @return
     */
    private Object translationPage(Object resultR, DataDeal annotation) throws Throwable {
        long s = System.currentTimeMillis();
        log.info("开始处理字典....");


        if (resultR == null) {
            return resultR;
        }
        PageVO page = (PageVO) resultR;
        Object result = page.getData();
        if (Objects.isNull(result)) {
            return resultR;
        }
        List dealList = (List) result;

        List resultList = new ArrayList();

        if (setParamValue(result,annotation)) {
            resultList.add(result);
            page.setData(resultList);
            return page;
        }

        for (Object temp : dealList) {
            resultList.add(translate(temp, annotation));
        }

        page.setData(resultList);


        // 返回处理后的数据
        log.info("字典处理完毕....结束时间为：{}毫秒", System.currentTimeMillis() - s);

        return page;
    }

}
